#pragma once
#include<iostream>
#include<string>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include"log.hpp"

const int backlog=10;
enum
{
    Sock_Err=1,
    Bind_Err,
    Listen_Err,

};
class Sock
{
public:
    Sock()
    {}
    ~Sock()
    {}
    void Socket()
    {
        sockfd=socket(AF_INET,SOCK_STREAM,0);
        if(sockfd<0)
        {
            log(Fatal,"socket err,sockfd: %d",sockfd);
            exit(Sock_Err);
        }
    }
    void Bind(uint16_t port)
    {
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(port);
        local.sin_addr.s_addr=INADDR_ANY;

        if(bind(sockfd,(struct sockaddr*)&local,sizeof(local))<0)
        {
            log(Fatal,"bind err,sockfd: %d",sockfd);
            exit(Bind_Err);
        }
    }

    void Listen()
    {
        if(listen(sockfd,backlog)<0)
        {
            log(Fatal,"listen success,sockfd: %d",sockfd);
            exit(Listen_Err);
        }
    }

    int Accept(uint16_t* port,std::string* ip)
    {
        struct sockaddr_in client;
        socklen_t len=sizeof(client);
        int newfd=accept(sockfd,(struct sockaddr*)&client,&len);
        if(newfd<0)
        {
            log(Fatal,"accept err");
            return -1;
        }
        *port=ntohs(client.sin_port);
        char buff[128];
        inet_ntop(AF_INET,&client.sin_addr,buff,sizeof(buff));
        *ip=buff;

        return newfd;
    }
    bool Connect(const uint16_t& port,const std::string& ip)
    {
        struct sockaddr_in server;
        memset(&server,0,sizeof(server));
        server.sin_family=AF_INET;
        server.sin_port=htons(port);
        inet_pton(AF_INET,ip.c_str(),&(server.sin_addr));
        
        int n=connect(sockfd,(struct sockaddr*)&server,sizeof(server));
        if(n<0)
        {
            std::cerr << "connect to " << ip << ":" << port << " error" << std::endl;
            return false;
        }
        return true;
    }
    void Close()
    {
        close(sockfd);
    }
    int GetFd()
    {
        return sockfd;
    }
private:
    int sockfd;
};